// Copyright 2010 The win Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package win

import (
	"runtime"
	"syscall"
	"unicode/utf8"
	"unsafe"
)

func init() {
	runtime.LockOSThread()
}

const (
	S_OK           = 0x00000000
	S_FALSE        = 0x00000001
	E_UNEXPECTED   = 0x8000FFFF
	E_NOTIMPL      = 0x80004001
	E_OUTOFMEMORY  = 0x8007000E
	E_INVALIDARG   = 0x80070057
	E_NOINTERFACE  = 0x80004002
	E_POINTER      = 0x80004003
	E_HANDLE       = 0x80070006
	E_ABORT        = 0x80004004
	E_FAIL         = 0x80004005
	E_ACCESSDENIED = 0x80070005
	E_PENDING      = 0x8000000A
)

const (
	FALSE = 0
	TRUE  = 1
)

type (
	BOOL    int32
	HRESULT int32
)

func MustLoadLibrary(name string) uintptr {
	lib, err := syscall.LoadLibrary(name)
	if err != nil {
		panic(err)
	}

	return uintptr(lib)
}

func MustGetProcAddress(lib uintptr, name string) uintptr {
	addr, err := syscall.GetProcAddress(syscall.Handle(lib), name)
	if err != nil {
		panic(err)
	}

	return uintptr(addr)
}

func SUCCEEDED(hr HRESULT) bool {
	return hr >= 0
}

func FAILED(hr HRESULT) bool {
	return hr < 0
}

func MAKEWORD(lo, hi byte) uint16 {
	return uint16(uint16(lo) | ((uint16(hi)) << 8))
}

func LOBYTE(w uint16) byte {
	return byte(w)
}

func HIBYTE(w uint16) byte {
	return byte(w >> 8 & 0xff)
}

func MAKELONG(lo, hi uint16) uint32 {
	return uint32(uint32(lo) | ((uint32(hi)) << 16))
}

func LOWORD(dw uint32) uint16 {
	return uint16(dw)
}

func HIWORD(dw uint32) uint16 {
	return uint16(dw >> 16 & 0xffff)
}

func UTF16PtrToString(s *uint16) string {
	if s == nil {
		return ""
	}
	return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
}

func MAKEINTRESOURCE(id uintptr) *uint16 {
	return (*uint16)(unsafe.Pointer(id))
}

func BoolToBOOL(value bool) BOOL {
	if value {
		return 1
	}

	return 0
}

// void * (uintptr)转换为字符串
func UINTptrToString(uintPtr uintptr) string {
	if uintPtr == 0 {
		return ""
	}

	return syscall.UTF16ToString((*[1 << 16]uint16)(unsafe.Pointer(uintPtr))[0:])
}

func UTF8PtrToSting(uintPtr uintptr) string {
	if uintPtr == 0 {
		return ""
	}

	tmpByte := (*[1 << 16]byte)(unsafe.Pointer(uintPtr))[0:]
	for i, v := range tmpByte {
		if v == 0 {
			tmpByte = tmpByte[0:i]
			break
		}
	}

	return UTF8Decode(tmpByte)
}

func UTF8Decode(b []byte) (str string) {
	for len(b) > 0 {
		s, size := utf8.DecodeRune(b)
		str += string(s)
		b = b[size:]
	}

	return
}

// 字符串转换
func StringToUintPtr(str string) uintptr {
	// fmt.Println("正在转换..", str)
	return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str)))
}

func StringToUTF16Ptr(str string) *uint16 {
	return syscall.StringToUTF16Ptr(str)
}

func StringToBytePtr(str string) *byte {
	return syscall.StringBytePtr(str)
}
